/****************************************Copyright (c)****************************************************

**--------------File Info---------------------------------------------------------------------------------
** File name:                sht30.c
** Last modified Date:       2024.11.28
** Last Version:             Ver:1.0
** Descriptions:             SHT30温湿度IC驱动
**
**--------------------------------------------------------------------------------------------------------
** Created by:               adm
** Created date:             2024.11.28
** Version:                  Ver:1.0
** Descriptions:             使用本驱动，需要调用i2c_application中间件
**--------------------------------------------------------------------------------------------------------*/
#include "sht30.h"

i2c_handle_type hi2c2_SHT30;


/**
  * @brief    CRC8校验函数
  * @param    待计算的数据指针，CRC计算数据长度
  * @retval   返回计算后的校验码
  */
uint8_t SHT30_CheckCrc8(uint8_t* const message, uint16_t len)
{
    uint8_t  remainder;     //余数
    uint8_t  i = 0, j = 0;  //循环变量

    /* 初始化 */
    remainder = 0xFF;

    for(j = 0; j < len; j++) {
        remainder ^= message[j];

        /* 从最高位开始依次计算  */
        for (i = 0; i < 8; i++) {
            if (remainder & 0x80) {
                remainder = (remainder << 1)^CRC8_POLYNOMIAL;
            } else {
                remainder = (remainder << 1);
            }
        }
    }

    /* 返回计算的CRC码 */
    return remainder;
}

/**
  * @brief    SHT30_Read_Status
  *           读取器件状态
  * @param    None
  * @retval   None
  */
uint16_t SHT30_Read_Status(uint8_t addr_select)
{
    uint8_t I2C_Transmit_Data[2];
    uint8_t I2C_Receive_Data[3] = {0};

    I2C_Transmit_Data[0] = SHT30_READSTATUS >> 8;
    I2C_Transmit_Data[1] = (uint8_t)SHT30_READSTATUS;

    if(addr_select == 0)
        i2c_master_transmit(&hi2c2_SHT30, SHT30_ADDRESS1, I2C_Transmit_Data, 2, 0x3FF);
    else if(addr_select == 1)
        i2c_master_transmit(&hi2c2_SHT30, SHT30_ADDRESS2, I2C_Transmit_Data, 2, 0x3FF);

    #if USE_RTOS
    vTaskDelay(10);
    #else
    wk_delay_ms(10);
    #endif

    if(addr_select == 0)
        i2c_master_receive(&hi2c2_SHT30, SHT30_ADDRESS1, I2C_Receive_Data, 3, 0x3FF);
    else if(addr_select == 1)
        i2c_master_receive(&hi2c2_SHT30, SHT30_ADDRESS2, I2C_Receive_Data, 3, 0x3FF);

    //忽略CRC字节，返回2字节器件状态
    return ((uint16_t)I2C_Receive_Data[0] << 8) | I2C_Receive_Data[1];
}

/**
  * @brief    SHT30_reset
  *           指令复位函数
  * @param    None
  * @retval   None
  */
void SHT30_reset(uint8_t addr_select)
{
    uint8_t I2C_Transmit_Data[2];

    I2C_Transmit_Data[0] = SHT30_SOFTRESET >> 8;
    I2C_Transmit_Data[1] = (uint8_t)SHT30_SOFTRESET;

    if(addr_select == 0)
        i2c_master_transmit(&hi2c2_SHT30, SHT30_ADDRESS1, I2C_Transmit_Data, 2, 0x3FF);
    else if(addr_select == 1)
        i2c_master_transmit(&hi2c2_SHT30, SHT30_ADDRESS2, I2C_Transmit_Data, 2, 0x3FF);

    #if USE_RTOS
    vTaskDelay(10);
    #else
    wk_delay_ms(10);
    #endif
}

/**
  * @brief    SHT30_heater
  *           开启/关闭加热器函数
  * @param    1 开启   0 关闭
  * @retval   None
  */
void SHT30_heater(uint8_t en, uint8_t addr_select)
{
    uint8_t I2C_Transmit_Data[2];

    if(en) {
        I2C_Transmit_Data[0] = SHT30_HEATEREN >> 8;
        I2C_Transmit_Data[1] = (uint8_t)SHT30_HEATEREN;
    } else {
        I2C_Transmit_Data[0] = SHT30_HEATERDIS >> 8;
        I2C_Transmit_Data[1] = (uint8_t)SHT30_HEATERDIS;
    }

    if(addr_select == 0)
        i2c_master_transmit(&hi2c2_SHT30, SHT30_ADDRESS1, I2C_Transmit_Data, 2, 0x3FF);
    else if(addr_select == 1)
        i2c_master_transmit(&hi2c2_SHT30, SHT30_ADDRESS2, I2C_Transmit_Data, 2, 0x3FF);
}


/**
  * @brief    SHT30_Read_Temperature_Humidity
  *           以高精度读取温湿度,不对CRC校验码做验证
  * @param    温度指针  湿度指针
  * @retval   SUCCESS 读取成功  ERROR 读取失败
  */
error_status SHT30_Read_Temperature_Humidity(float *Temperature, float *Humidity, uint8_t addr_select)
{
    uint16_t ST, SRH;
    uint8_t I2C_Transmit_Data[2];
    uint8_t I2C_Receive_Data[6] = {0};

    I2C_Transmit_Data[0] = SHT30_MEAS_HIGHREP >> 8;
    I2C_Transmit_Data[1] = (uint8_t)SHT30_MEAS_HIGHREP;

    if(addr_select == 0) {
        if(i2c_master_transmit(&hi2c2_SHT30, SHT30_ADDRESS1, I2C_Transmit_Data, 2, 0x3FF) != I2C_OK) return ERROR;
    }
    else if(addr_select == 1) {
        if(i2c_master_transmit(&hi2c2_SHT30, SHT30_ADDRESS2, I2C_Transmit_Data, 2, 0x3FF) != I2C_OK) return ERROR;
    }

    #if USE_RTOS
    vTaskDelay(15);         //此处必须15ms延时，等待内部测量完成
    #else
    wk_delay_ms(15);
    #endif

    if(addr_select == 0) {
        if(i2c_master_receive(&hi2c2_SHT30, SHT30_ADDRESS1, I2C_Receive_Data, 6, 0x3FF) != I2C_OK) return ERROR;
    }
    else if(addr_select == 1) {
        if(i2c_master_receive(&hi2c2_SHT30, SHT30_ADDRESS2, I2C_Receive_Data, 6, 0x3FF) != I2C_OK) return ERROR;
    }

    /* 对获取的温湿度值进行换算 */
    ST = I2C_Receive_Data[0];
    ST <<= 8;
    ST |= I2C_Receive_Data[1];

    if (I2C_Receive_Data[2] != SHT30_CheckCrc8(I2C_Receive_Data, 2) != I2C_OK) return ERROR;    //CRC校验不过退出

    SRH = I2C_Receive_Data[3];
    SRH <<= 8;
    SRH |= I2C_Receive_Data[4];

    if (I2C_Receive_Data[5] != SHT30_CheckCrc8(I2C_Receive_Data + 3, 2) != I2C_OK) return ERROR; //CRC校验不过退出

    double stemp = ST;
    stemp *= 175;
    stemp /= 0xFFFF;
    stemp = -45 + stemp;
    *Temperature = stemp;

    double shum = SRH;
    shum *= 100;
    shum /= 0xFFFF;
    *Humidity = shum;

    return SUCCESS;
}


/**
  * @brief    SHT30初始化
  * @param    None
  * @retval   None
  */
void SHT30_Init(void)
{
    hi2c2_SHT30.i2cx = I2C2;
    i2c_config(&hi2c2_SHT30);
}
